
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       sensor_compass_backend.h
  * @author     baiyang
  * @date       2021-11-24
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include <rtthread.h>

#include <common/gp_math/gp_mathlib.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/
/*
  device driver IDs. These are used to fill in the devtype field
  of the device ID, which shows up as COMPASS*ID* parameters to
  users. The values are chosen for compatibility with existing PX4
  drivers.
  If a change is made to a driver that would make existing
  calibration values invalid then this number must be changed.
 */
enum CompassDevTypes {
    COMPASS_DEVTYPE_HMC5883_OLD = 0x01,
    COMPASS_DEVTYPE_HMC5883 = 0x07,
    COMPASS_DEVTYPE_LSM303D = 0x02,
    COMPASS_DEVTYPE_AK8963  = 0x04,
    COMPASS_DEVTYPE_BMM150  = 0x05,
    COMPASS_DEVTYPE_LSM9DS1 = 0x06,
    COMPASS_DEVTYPE_LIS3MDL = 0x08,
    COMPASS_DEVTYPE_AK09916 = 0x09,
    COMPASS_DEVTYPE_IST8310 = 0x0A,
    COMPASS_DEVTYPE_ICM20948 = 0x0B,
    COMPASS_DEVTYPE_MMC3416 = 0x0C,
    COMPASS_DEVTYPE_QMC5883L = 0x0D,
    COMPASS_DEVTYPE_MAG3110  = 0x0E,
    COMPASS_DEVTYPE_SITL  = 0x0F,
    COMPASS_DEVTYPE_IST8308 = 0x10,
    COMPASS_DEVTYPE_RM3100 = 0x11,
    COMPASS_DEVTYPE_RM3100_2 = 0x12, // unused, past mistake
    COMPASS_DEVTYPE_MMC5983 = 0x13,
    COMPASS_DEVTYPE_AK09918 = 0x14,
    COMPASS_DEVTYPE_AK09915 = 0x15,
};

/**
  * @brief       
  * @param[out]  
  * @retval      
  * @note        
  */
typedef struct {
    struct sensor_compass_backend_ops *ops;

    // mutex for access to shared frontend data
    rt_mutex_t _mutex;

    // mean field length for range filter
    float _mean_field_length;

    // number of dropped samples. Not used for now, but can be usable to choose more reliable sensor
    uint32_t _error_count;
} sensor_compass_backend;

/**
 * sensor compass operators
 */
struct sensor_compass_backend_ops {
    void (*compass_backend_destructor)(sensor_compass_backend *compass_backend);

    // each driver must provide an update method to copy accumulated
    // data to the frontend
    void (*read)(sensor_compass_backend *compass_backend);
};
/*----------------------------------variable----------------------------------*/
extern struct sensor_compass_backend_ops compass_backend_ops;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void sensor_compass_backend_ctor(sensor_compass_backend *compass_backend, char *name);
void sensor_compass_backend_rotate_field(Vector3f_t *mag, uint8_t instance);
void sensor_compass_backend_publish_raw_field(const Vector3f_t *mag, uint8_t instance);
void sensor_compass_backend_accumulate_sample(sensor_compass_backend *compass_backend, Vector3f_t *field, uint8_t instance, uint32_t max_samples);
void sensor_compass_backend_drain_accumulated_samples(sensor_compass_backend *compass_backend, uint8_t instance, const Vector3f_t *scaling);
void sensor_compass_backend_correct_field(Vector3f_t *mag, uint8_t i);
void sensor_compass_backend_publish_filtered_field(const Vector3f_t *mag, uint8_t instance);
void sensor_compass_backend_set_last_update_usec(uint64_t last_update, uint8_t instance);
bool sensor_compass_backend_register_compass(int32_t dev_id, uint8_t* instance);
void sensor_compass_backend_set_dev_id(uint8_t instance, uint32_t dev_id);
void sensor_compass_backend_save_dev_id(uint8_t instance);
void sensor_compass_backend_set_external(uint8_t instance, bool external);
bool sensor_compass_backend_is_external(uint8_t instance);
void sensor_compass_backend_set_rotation(uint8_t instance, enum RotationEnum rotation);
bool sensor_compass_backend_field_ok(sensor_compass_backend *compass_backend, const Vector3f_t *field);
enum RotationEnum sensor_compass_backend_get_board_orientation(void);

static inline void sensor_compass_backend_destructor(sensor_compass_backend *compass_backend) {
    if (compass_backend->ops->compass_backend_destructor != NULL) {
        compass_backend->ops->compass_backend_destructor(compass_backend);
    }
}

static inline void sensor_compass_backend_read(sensor_compass_backend *compass_backend) {
    if (compass_backend->ops->read != NULL) {
        compass_backend->ops->read(compass_backend);
    }
}

/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



